﻿using System.IO;
using System.Linq;
using NUnit.Framework;
using System;
using System.Collections.Generic;

namespace Twitter.Tests
{
	[TestFixture]
	public class FriendshipFixture : TestBase
	{
		[ExpectedException(typeof(ArgumentNullException))]
		[Test]
		public void ShouldThrowIfNullLeaveUserId()
		{
			TestRun.CreateClient().Friendship.Leave(null);
		}

		[ExpectedException(typeof(ArgumentException))]
		[Test]
		public void ShouldThrowIfEmptyLeaveUserId()
		{
			TestRun.CreateClient().Friendship.Leave("");
		}

		[Test]
		public void ShouldAddFriendAndFollowerWhenFollowingUser()
		{
			IBotClient bot;
			IBotClient client;
			TestRun.CreateClients(out bot, out client);

			// Starting cleanup
			bot.Friendship.Leave(TestRun.ClientScreenName);
			client.Friendship.Leave(TestRun.BotScreenName);

			Assert.IsFalse(bot.Friendship.GetFollowers().Contains(TestRun.BotScreenName));
			Assert.IsFalse(client.Friendship.GetFollowers().Contains(TestRun.ClientScreenName));
			Assert.IsFalse(client.Friendship.GetFriends().Contains(TestRun.BotScreenName));
			Assert.IsFalse(bot.Friendship.GetFriends().Contains(TestRun.ClientScreenName));

			client.Friendship.Follow(TestRun.BotScreenName);

			Assert.IsTrue(bot.Friendship.GetFollowers().Contains(TestRun.ClientScreenName));
			Assert.IsTrue(client.Friendship.GetFriends().Contains(TestRun.BotScreenName));
		}

		[Test]
		public void ShouldFollowFriendAndGetFriends()
		{
			IBotClient bot;
			IBotClient userClient;
			TestRun.CreateClients(out bot, out userClient);

			userClient.Friendship.Follow(TestRun.BotScreenName);

			Assert.IsTrue(userClient.Friendship.GetFriends().Contains(TestRun.BotScreenName));
		}

		[Test]
		public void ShouldMakeNewFriendAndFollowThem()
		{
			IBotClient bot;
			IBotClient client;
			TestRun.CreateClients(out bot, out client);

			// Cleanup just in case.
			client.Friendship.Leave(TestRun.BotScreenName);
			bot.Friendship.Leave(TestRun.ClientScreenName);

			Assert.IsFalse(bot.Friendship.GetFollowers().Contains(TestRun.ClientScreenName));

			client.Friendship.Follow(TestRun.BotScreenName);

			Assert.IsTrue(bot.Friendship.GetFollowers().Contains(TestRun.ClientScreenName));

			var friends = bot.Friendship.MakeFriends().ToList();

			Assert.That(friends.Contains(TestRun.ClientScreenName));
			Assert.That(bot.Friendship.GetFriends().Contains(TestRun.ClientScreenName));
		}

		[Test]
		public void ShouldFollowFollowingUsers()
		{
			IBotClient bot;
			IBotClient client;
			TestRun.CreateClients(out bot, out client);

			Assert.That(!bot.Friendship.GetFriends().Contains(TestRun.ClientScreenName));
			Assert.That(!bot.Friendship.GetFollowers().Contains(TestRun.ClientScreenName));

			client.Friendship.Follow(TestRun.BotScreenName);

			try
			{
				Assert.That(bot.Friendship.GetFollowers().Contains(TestRun.ClientScreenName));
				Assert.That(!(bot.Friendship.GetFriends().Contains(TestRun.ClientScreenName)));

				IEnumerable<string> newFriends = bot.Friendship.MakeFriends();

				Assert.That(newFriends.Contains(TestRun.ClientScreenName));
				Assert.That(bot.Friendship.GetFriends().Contains(TestRun.ClientScreenName));
				Assert.That(client.Friendship.GetFollowers().Contains(TestRun.BotScreenName));
			}
			finally
			{
				bot.Friendship.Leave(TestRun.ClientScreenName);
				client.Friendship.Leave(TestRun.BotScreenName);
				Assert.That(!(bot.Friendship.GetFollowers().Contains(TestRun.ClientScreenName)));
				Assert.That(!(client.Friendship.GetFollowers().Contains(TestRun.BotScreenName)));
			}
		}

		[Test]
		public void ShouldLeaveFriend()
		{
			IBotClient bot;
			IBotClient client;
			TestRun.CreateClients(out bot, out client);

			client.Friendship.Follow(TestRun.BotScreenName);
			bot.Friendship.Follow(TestRun.ClientScreenName);

			int botFriends = bot.Friendship.GetFriends().Count();
			int clientFollowers = client.Friendship.GetFollowers().Count();

			bot.Friendship.Leave(TestRun.ClientScreenName);

			Assert.AreEqual(botFriends - 1, bot.Friendship.GetFriends().Count());
			Assert.AreEqual(clientFollowers - 1, client.Friendship.GetFollowers().Count());
		}

		[Test]
		public void ShouldFollow()
		{
			IBotClient bot;
			IBotClient client;
			TestRun.CreateClients(out bot, out client);

			client.Friendship.Leave(TestRun.BotScreenName);
			bot.Friendship.Leave(TestRun.ClientScreenName);

			Assert.IsTrue(bot.Friendship.Follow(TestRun.ClientScreenName));

			// Second time should also be true if already following.
			Assert.IsTrue(bot.Friendship.Follow(TestRun.ClientScreenName));
		}

		[Test]
		public void ShouldTestMutualFriendOf()
		{
			IBotClient bot;
			IBotClient client;
			TestRun.CreateClients(out bot, out client);

			bot.Friendship.Leave(TestRun.ClientScreenName);
			client.Friendship.Leave(TestRun.BotScreenName);

			Assert.IsFalse(bot.Friendship.IsMutualFriendOf(TestRun.ClientScreenName));
			Assert.IsFalse(client.Friendship.IsMutualFriendOf(TestRun.BotScreenName));

			bot.Friendship.Follow(TestRun.ClientScreenName);

			Assert.IsFalse(bot.Friendship.IsMutualFriendOf(TestRun.ClientScreenName));
			Assert.IsFalse(client.Friendship.IsMutualFriendOf(TestRun.BotScreenName));

			client.Friendship.Follow(TestRun.BotScreenName);

			Assert.IsTrue(bot.Friendship.IsMutualFriendOf(TestRun.ClientScreenName));
			Assert.IsTrue(client.Friendship.IsMutualFriendOf(TestRun.BotScreenName));
		}

		[Test]
		public void ShouldTestMutualFriends()
		{
			IBotClient bot;
			IBotClient client;
			TestRun.CreateClients(out bot, out client);

			bot.Friendship.Leave(TestRun.ClientScreenName);
			client.Friendship.Leave(TestRun.BotScreenName);

			Assert.IsFalse(bot.Friendship.AreMutualFriends(TestRun.BotScreenName, TestRun.ClientScreenName));

			bot.Friendship.Follow(TestRun.ClientScreenName);

			Assert.IsFalse(bot.Friendship.AreMutualFriends(TestRun.BotScreenName, TestRun.ClientScreenName));

			client.Friendship.Follow(TestRun.BotScreenName);

			Assert.IsTrue(bot.Friendship.AreMutualFriends(TestRun.BotScreenName, TestRun.ClientScreenName));
		}

		[Test]
		public void ShouldTestFriendOf()
		{
			IBotClient bot;
			IBotClient client;
			TestRun.CreateClients(out bot, out client);

			bot.Friendship.Leave(TestRun.ClientScreenName);
			client.Friendship.Leave(TestRun.BotScreenName);

			Assert.IsFalse(bot.Friendship.IsFriendOf(TestRun.ClientScreenName));

			bot.Friendship.Follow(TestRun.ClientScreenName);

			Assert.IsTrue(bot.Friendship.IsFriendOf(TestRun.ClientScreenName));
		}

		[Test]
		public void ShouldTestUserFriendOf()
		{
			IBotClient bot;
			IBotClient client;
			TestRun.CreateClients(out bot, out client);

			bot.Friendship.Leave(TestRun.ClientScreenName);
			client.Friendship.Leave(TestRun.BotScreenName);

			Assert.IsFalse(bot.Friendship.IsFriendOf(TestRun.BotScreenName, TestRun.ClientScreenName));

			bot.Friendship.Follow(TestRun.ClientScreenName);

			Assert.IsTrue(bot.Friendship.IsFriendOf(TestRun.BotScreenName, TestRun.ClientScreenName));
		}

		[Test]
		public void ShouldCleanupNonFollowingFriends()
		{
			IBotClient bot;
			IBotClient userClient;
			TestRun.CreateClients(out bot, out userClient);

			userClient.Friendship.Leave(TestRun.BotScreenName);
			bot.Friendship.Follow(TestRun.ClientScreenName);

			var lostFriends = bot.Friendship.ForgetLostFriends().ToList();

			Assert.AreEqual(1, lostFriends.Count);
			Assert.AreEqual(TestRun.ClientScreenName, lostFriends[0]);
		}
	}
}
